﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using Services.Equ.PcapCommunication.Abstract;
using SharpPcap;

namespace Services.Equ.PcapCommunication.Operation
{
    /// <summary>
    /// 抽象操作类，部分通讯需要先建立连接再进行操作
    /// </summary>
    public class PcapOperation<T>
    {
        /// <summary>
        /// 建立连接通讯类
        /// </summary>
        public AbstractPcapCommunication<bool> ConnetCommunication { get; set; }
        /// <summary>
        /// 释放链接通讯类
        /// </summary>
        public AbstractPcapCommunication<bool> ReleaseCommunication { get; set; }
        /// <summary>
        /// 需要实现的操作通讯类
        /// </summary>
        public List<AbstractPcapCommunication<T>> PcapCommunications { get; set; }
        /// <summary>
        /// 每个操作类是否自行控制网卡开关
        /// </summary>
        public bool IsAutoControlDevice { get; set; } = true;
        /// <summary>
        /// 网卡
        /// </summary>
        public ILiveDevice Device { get=> PcapCommunications.First().Device; }
        /// <summary>
        /// 目标设备mac地址
        /// </summary>
        public PhysicalAddress DestinationMac { get=> PcapCommunications.First().DestinationMac; }
        /// <summary>
        /// 建立连接重试次数
        /// </summary>
        public int ReConnetTimes { get; set; } = 2;

        public PcapOperation(params AbstractPcapCommunication<T>[] pcapCommunication)
        {
            PcapCommunications = [.. pcapCommunication];
            InitCommunication(PcapCommunications.First().DestinationMac, PcapCommunications.First().Password, PcapCommunications.First().Device);
        }
        public PcapOperation(IEnumerable<AbstractPcapCommunication<T>> pcapCommunications)
        {
            PcapCommunications = [.. pcapCommunications];
            InitCommunication(PcapCommunications.First().DestinationMac, PcapCommunications.First().Password, PcapCommunications.First().Device);
            
        }
        private void InitCommunication(PhysicalAddress destinationMac, string password,ILiveDevice device)
        {
            ConnetCommunication = new ConnectCommunication(destinationMac, password, device);
            ConnetCommunication.IsAutoControlDevice = IsAutoControlDevice;
            ReleaseCommunication = new ReleaseCommunication(destinationMac, password, device);
            ReleaseCommunication.IsAutoControlDevice= IsAutoControlDevice;
            PcapCommunications.ForEach(t=>t.IsAutoControlDevice=IsAutoControlDevice);
        }

        /// <summary>
        /// 获取通讯结果
        /// </summary>
        /// <returns>返回一个字典，字典的key为构造函数放入通讯类的顺序(从0开始),value为此通讯类返回的结果</returns>
        public virtual async Task<Dictionary<int,List<T>>?> GetOperationResult()
        {
            Dictionary<int, List<T>> dic = [];
            int i = 0;
            SetUUID();
            bool isConnet = false;
            var r = 0;
            try
            {
                if (!IsAutoControlDevice)
                {
                    Device.Open();
                    //Device.Filter = Filter;
                }
                while (!isConnet && r <= ReConnetTimes)
                {
                    var result = await ConnetCommunication.GetCommunicationResult();
                    if (result.Any(t => t == true))
                    {
                        isConnet = true;
                        break;
                    }
                    else
                    {
                        await ReleaseCommunication.GetCommunicationResult();
                        SetUUID();
                        r++;
                    }
                }
                if (isConnet)
                {
                    foreach (var communication in PcapCommunications)
                    {
                        communication.SeqId = i + 1;
                        var result = await communication.GetCommunicationResult();
                        dic.Add(i, result);
                        i++;
                    }
                    ReleaseCommunication.SeqId = i + 1;
                    await ReleaseCommunication.GetCommunicationResult();
                    if (!IsAutoControlDevice)
                    {
                        Device.StopCapture();
                        Device.Close();
                    }
                    return dic;
                }
                else
                {
                    return null;
                }
            }
            finally
            {
                if (IsAutoControlDevice)
                {
                    Device.StopCapture();
                    Device.Close();
                }
            }
            
        }
        protected void SetUUID()
        {
            var uuid = Guid.NewGuid().ToByteArray();
            //byte[] uuid = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
            ConnetCommunication.UUID = uuid;
            ReleaseCommunication.UUID = uuid;
            PcapCommunications.ForEach(t=>t.UUID = uuid);
        }
    }
}
